module alu(in_x,in_y,sel,out_s);
  input [3:0] in_x;
  input [3:0] in_y;
  input [2:0] sel;
  output [3:0] out_s;
  reg [3:0] out_s;
  reg sub;
  reg carry;
  reg overflow;
  reg zero;
  wire[3:0] addr_out;
  addr #(4) addr1 (
	 .A(in_x),
       	.B(in_y),
       .sub(sub),
        .out_s(addr_out),
	.carry(carry),
	.overflow(overflow),
	.zero(zero)
  );
  // +, -, not, and, or, xor, ><, ==
  always @(in_x or in_y or sel) begin
    case (sel)
      3'b010: out_s = in_x ^ '1;//{4{1'b1}};
      3'b011: out_s = in_x & in_y;
      3'b100: out_s = in_x | in_y;
      3'b101: out_s = in_x ^ in_y;
      default: begin
          if (sel==3'b000) sub = 0;
	  else
		  sub = 1;
	  if (sel==3'b111) out_s = 4'(zero);
	  else if (sel==3'b110)begin
		  out_s = {3'b0, addr_out[3]^overflow};
	  end
	  else begin
		  out_s = addr_out;
	  end
      end
    endcase
  end
endmodule

module addr #(N_BIT = 4) (A,B,sub,out_s, carry, zero, overflow);
  input [3:0] A;
  input [3:0] B;
  input sub;
  output [3:0] out_s;
  output carry;
  output zero;
  output overflow;
  
  wire [N_BIT-1:0] t_no_Cin;
  assign t_no_Cin = {N_BIT{sub}}^B;
  assign {carry, out_s} = A + t_no_Cin + N_BIT'(sub);
  assign overflow = (A[N_BIT-1]==t_no_Cin[N_BIT-1]) && (out_s[N_BIT-1]!=A[N_BIT-1]);
  assign zero = ~(|out_s);
endmodule
